﻿using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Shared = Faust.Andrew.MTG.Player.Shared;

namespace Faust.Andrew.MTG.Player
{
    class MTGServerProxy : Shared.IMTGServer
    {
        private string _host;
        private int _port;
        private Shared.IMTGServer _channel;

        protected Shared.IMTGServer Channel
        {
            get
            {
                if (_channel == null)
                {
                    _channel = CreateChannel(_host, _port);
                }
                else
                {
                    IClientChannel clientChannel = (IClientChannel)_channel;
                    if (clientChannel.State != CommunicationState.Opened)
                    {
                        if (clientChannel.State == CommunicationState.Faulted)
                        {
                            clientChannel.Abort();
                        }
                        else
                        {
                            clientChannel.Close();
                        }
                        ((IDisposable)_channel).Dispose();

                        _channel = CreateChannel(_host, _port);
                    }
                }

                return _channel;
            }
        }

        protected Shared.IMTGServer CreateChannel(string host, int port)
        {
            string endpointAddress = String.Format("net.tcp://{0}", host);
            if (port > 0)
            {
                endpointAddress += String.Format(":{0}", port);
            }

            NetTcpBinding binding = new NetTcpBinding();
            binding.MaxBufferPoolSize = Int32.MaxValue;
            binding.MaxBufferSize = Int32.MaxValue;
            binding.MaxConnections = 300;
            binding.MaxReceivedMessageSize = Int32.MaxValue;
            binding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.None;
            binding.Security.Mode = SecurityMode.None;
            binding.Security.Message.ClientCredentialType = MessageCredentialType.None;


            ServiceEndpoint endPoint = new ServiceEndpoint(
                ContractDescription.GetContract(typeof(Shared.IMTGServer)),
                binding,
                new EndpointAddress(endpointAddress));

            return new ChannelFactory<Shared.IMTGServer>(endPoint).CreateChannel();
        }

        public MTGServerProxy(string host, int port)
        {
            _host = host;
            _port = port;

            _channel = CreateChannel(_host, _port);
        }

        #region IMTGServer Members

        public int JoinGame(string playerName, Deck deck)
        {
            return Channel.JoinGame(playerName, deck);
        }

        public int RejoinGame(string playerName)
        {
            return Channel.RejoinGame(playerName);
        }

        /*
        public void StartGame()
        {
            Channel.StartGame();
        }

        public void EndGame()
        {
            Channel.EndGame();
        }
        */

        public Queue<Faust.Andrew.MTG.Player.Shared.Action> Poll(int playerId)
        {
            return Channel.Poll(playerId);
        }

        public void SendMessage(int playerId, List<int> targetPlayersIds, string message)
        {
            Channel.SendMessage(playerId, targetPlayersIds, message);
        }

        public void ShowCards(int playerID, List<int> targetPlayersIDs, List<int> cardIds)
        {
            Channel.ShowCards(playerID, targetPlayersIDs, cardIds);
        }

        public void Notify(int playerId, string message)
        {
            Channel.Notify(playerId, message);
        }

        public void RefreshGameState(int playerId)
        {
            Channel.RefreshGameState(playerId);
        }

        public bool UpdateCard(int playerID, Faust.Andrew.MTG.Player.Shared.GameCard card)
        {
            return Channel.UpdateCard(playerID, card);
        }

        public bool MarkCard(int playerId, int cardId, bool isMarked)
        {
            return Channel.MarkCard(playerId, cardId, isMarked);
        }

        public bool MoveCard(int playerId, int cardId, Faust.Andrew.MTG.Player.Shared.Location location)
        {
            return Channel.MoveCard(playerId, cardId, location);
        }

        public bool TransferCard(int playerId, int targetPlayerId, int cardId)
        {
            return Channel.TransferCard(playerId, targetPlayerId, cardId);
        }

        public bool UpdatePlayer(int playerId, Faust.Andrew.MTG.Player.Shared.Player player)
        {
            return Channel.UpdatePlayer(playerId, player);
        }

        public Shared.GameCard DrawCard(int playerId)
        {
            return Channel.DrawCard(playerId);
        }

        public void PlayTokenCreature(int playerId, string tokenText, string imageKey, int quantity)
        {
            Channel.PlayTokenCreature(playerId, tokenText, imageKey, quantity);
        }

        public void RemoveTokenCreature(int playerId, int cardId)
        {
            Channel.RemoveTokenCreature(playerId, cardId);
        }

        public List<Shared.GameCard> DrawCards(int playerId, int count)
        {
            return Channel.DrawCards(playerId, count);
        }

        public bool ShuffleDeck(int playerId)
        {
            return Channel.ShuffleDeck(playerId);
        }

        public List<Shared.GameCard> GetCardList(int playerId, int targetPlayerId, Shared.Zone zone)
        {
            return Channel.GetCardList(playerId, targetPlayerId, zone);
        }

        public bool SendCardToDeck(int playerId, int cardId, Shared.DeckPosition deckPosition, int offset)
        {
            return Channel.SendCardToDeck(playerId, cardId, deckPosition, offset);
        }

        public int RollDie(int playerId, int sides)
        {
            return Channel.RollDie(playerId, sides);
        }

        public void EndTurn(int playerId)
        {
            Channel.EndTurn(playerId);
        }

        public void AttemptPlaneswalk(int playerId)
        {
            Channel.AttemptPlaneswalk(playerId);
        }

        public void RandomReveal(int playerId, int count, Shared.Zone sourceZone, List<int> targetPlayers)
        {
            Channel.RandomReveal(playerId, count, sourceZone, targetPlayers);
        }

        public void RandomDiscard(int playerId, int count, Shared.Zone sourceZone)
        {
            Channel.RandomDiscard(playerId, count, sourceZone);
        }
        #endregion
    }
}
